/*
 * StabSolvers.h
 *
 *  Created on: Sep 19, 2011
 *      Author: correa
 */

#ifndef IPSTABSOLVERS_H_
#define IPSTABSOLVERS_H_

#include <Graph.h>
#include <StabSolver.h>
#include <cplex.h>

class Stab : public StabSolver {
	friend class StabSolver;
protected:
	int 			lb;
	int *			S;

	int				erowbeg;
	int				erowend;
	int				crowbeg;
	int				crowend;

	StabModeler * 	sm;
	Weight<double> *w;

	// cplex environment
	CPXENVptr 		cpxenv;
	// base solver
	CPXLPptr 		solver;

	template <class M, class G>
	Stab(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w);
	template <class M, class G>
	Stab(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w, int col, const char * prefix);

	Stab(Graph * g, Weight<double> * w);

	CPXLPptr opensolver();
	int build(StabModeler * bsm, int *erb, int *ere, int *crb, int *cre, int *ub, CPXLPptr solver);
	void setlb(Graph * g, int k);

public:
	virtual ~Stab();
	virtual int objective() = 0;
	virtual int solveByEnumeration();
	virtual int getBest(double * val);
	virtual int getNodes(int * nnd);
};

class MaxStab : public Stab {
	int					n;
	bool				unit;
public:
	~MaxStab();
	virtual int objective();
	template <class M, class G>
	MaxStab(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w);
	template <class M, class G>
	MaxStab(Graph * g, ModelerFactory<M,G> * fm);
	template <class M, class G>
	MaxStab(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w, int col, const char * prefix);
	template <class M, class G>
	MaxStab(Graph * g, ModelerFactory<M,G> * fm, int col, const char * prefix);
	virtual int solveByEnumeration();
};

class RepStab : public Stab {
	friend class StabSolver;

private:
	int status;
	void init(Graph * g);
protected:
	int				n;
	RepModeler *	rm;
	StabModeler **	repm;
	int *			ub;
	int				nactive;
	int	*			active;
	RepStab(Graph * g, Weight<double> * w);
	template <class M, class G>
	RepStab(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w);
	template <class M, class G>
	RepStab(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w, int col, const char * prefix);
	void build(int k);
public:
	virtual ~RepStab();
};

class MaxRepStab : public RepStab {
	bool				unit;
	void init(int k);
public:
	~MaxRepStab();
	virtual int objective();
	template <class M, class G>
	MaxRepStab(Graph * g, ModelerFactory<M,G> * fm, int k);
	template <class M, class G>
	MaxRepStab(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w, int k);
	template <class M, class G>
	MaxRepStab(Graph * g, ModelerFactory<M,G> * fm, int col, const char * prefix, int k);
	template <class M, class G>
	MaxRepStab(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w, int col, const char * prefix, int k);
	virtual int solveByEnumeration();
};

class RepColor : public MaxRepStab {
public:
	~RepColor();
	virtual int objective();
	template <class M, class G>
	RepColor(Graph * g, ModelerFactory<M,G> * fm, int k);
	template <class M, class G>
	RepColor(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w, int k);
	template <class M, class G>
	RepColor(Graph * g, ModelerFactory<M,G> * fm, int col, const char * prefix, int k);
	template <class M, class G>
	RepColor(Graph * g, ModelerFactory<M,G> * fm, Weight<double> * w, int col, const char * prefix, int k);
	virtual int solveByEnumeration();
};

template <class M, class G>
inline StabSolver * StabSolver::create(string relax, Graph * g, ModelerFactory<M,G> * fm, int k) {
	if (relax == "linear" || relax == "alinear")
		return k >= 1 ? new MaxRepStab(g, fm, k) : new RepColor(g, fm, g->nverts());
	return NULL;
}

template <class M, class G>
inline StabSolver * StabSolver::create(Graph * g, ModelerFactory<M,G> * fm) {
	return new MaxStab(g, fm);
}

#endif /* STABSOLVERS_H_ */
